package com.enerccio.commonJ.tools;

import java.util.HashMap;
import java.util.Map;

/**
 * SpecialVariable is an object that holds value in it for every single thread that is 
 * trying to access it. The thread id is used as identifier for method get and set and so
 * every thread can only access it's own variable.
 * @author enerccio
 *
 * @param <T>
 */
public class SpecialVariable<T> implements GetSet<T>{
	
	/**
	 * Returns variable held by thread. Useful for debug.
	 * @param variable SpecialVariable instance
	 * @param thread thread we are curious about
	 * @return
	 */
	public static synchronized <V> V getValue(SpecialVariable<V> variable, Thread thread){
		return variable.getThreadValue(thread.getId());
	}
	
	/**
	 * Sets the variable held by thread. Useful for debug.
	 * @param variable SpecialVariable instance
	 * @param thread thread we are curious about
	 * @param value value we want to set to that SpecialVariable
	 */
	public static synchronized <V> void setValue(SpecialVariable<V> variable, 
			Thread thread, V value){
		variable.setThreadValue(thread.getId(), value);
	}
	
	/** This map holds the actual values */
	private Map<Long, T> dataMap;
	
	/** Creates new special variable with initial value set */
	public SpecialVariable(T value){
		dataMap = new HashMap<Long, T>();
		set(value);
	}

	@Override
	public synchronized T get() {
		Long tId = Thread.currentThread().getId();
		return getThreadValue(tId);
	}
	
	/**
	 * Inner implementation of get method.
	 * @param tId
	 * @return
	 */
	private T getThreadValue(long tId){
		return dataMap.get(tId);
	}

	@Override
	public synchronized void set(T value) {
		Long tId = Thread.currentThread().getId();
		setThreadValue(tId, value);
	}
	
	/**
	 * Inner implementation of set method.
	 * @param tId
	 * @param value
	 */
	private void setThreadValue(Long tId, T value) {
		dataMap.put(tId, value);
	}

	@Override
	public synchronized String toString(){
		return get().toString();
	}

}
